import * as THREE from 'three'
import * as d3 from 'd3'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { CSS2DObject, CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
import jiangsu from '../json/jiangsu.json'
import jiangsuout from '../json/jiangsuout.json'

let renderer, scene, camera, orbitControls, map, labelRenderer
let projectpos = d3.geoMercator().center([119.77, 33.03]).scale(600).translate([0, 0])
function init() {
    initRenderer()
    initScene()
    initCamera()
    initHelp()
    initGeoJson()
    initControls()
    animate()
}
function initRenderer() {
    renderer = new THREE.WebGLRenderer()
    renderer.setSize(document.getElementById('webgl-out').clientWidth, document.getElementById('webgl-out').clientHeight)
    document.getElementById('webgl-out').appendChild(renderer.domElement)

    labelRenderer = new CSS2DRenderer()
    labelRenderer.setSize(document.getElementById('webgl-out').clientWidth, document.getElementById('webgl-out').clientHeight)
    labelRenderer.domElement.style.position = 'absolute'
    labelRenderer.domElement.style.top = '0px'
    labelRenderer.domElement.style.pointerEvents = 'none'
    document.getElementById('webgl-out').appendChild(labelRenderer.domElement)
}

function initScene() {
    scene = new THREE.Scene()
}

function initCamera() {
    camera = new THREE.PerspectiveCamera(45, document.getElementById('webgl-out').clientWidth / document.getElementById('webgl-out').clientHeight, 0.1, 1000)
    camera.position.set(50, 50, 50)
    camera.lookAt(scene.position)
}

function initHelp() {
    let axes = new THREE.AxesHelper(1000)
    scene.add(axes)
}

function initControls() {
    orbitControls = new OrbitControls(camera, renderer.domElement)
}

function initGeoJson() {
    map = new THREE.Group()
    initMap(jiangsuout)
    initMapLine(jiangsu)
}

function initMap(jiangsuout) {
    const material = new THREE.MeshBasicMaterial({
        color: 0x113c76,
        transparent: true,
        opacity: 0.7
    })
    jiangsuout.features.forEach(elem => {
        const province = new THREE.Object3D()
        let { coordinates } = elem.geometry
        coordinates.forEach(multPolygon => {
            multPolygon.forEach(polygon => {
                const shape = new THREE.Shape()
                for (let i = 0; i < polygon.length; i++) {
                    let [x, y] = projectpos(polygon[i])
                    if (!isNaN(x)) {
                        shape.moveTo(x, -y)
                    }
                    shape.lineTo(x, -y)
                }
                const extrudsSettings = {
                    depth: 2
                }
                const geometry = new THREE.ExtrudeGeometry(shape, extrudsSettings)
                const mesh = new THREE.Mesh(geometry, material)
                mesh.rotateX(-Math.PI / 2)
                province.add(mesh)
            })
        })
        map.add(province)
    })
    scene.add(map)
}
function initMapLine(jiangsu) {
    jiangsu.features.forEach(elem => {
        const province = new THREE.Object3D()
        let { coordinates } = elem.geometry
        initText(elem.properties)
        coordinates.forEach(multPolygon => {
            multPolygon.forEach(polygon => {
                const lineMaterial = new THREE.LineBasicMaterial({
                    color: 'white'
                })
                const lineGeometry = new THREE.BufferGeometry()
                let pointerArr = []
                for (let i = 0; i < polygon.length; i++) {
                    let [x, y] = projectpos(polygon[i])
                    if (!isNaN(x)) {
                        pointerArr.push(x, -y, 2.01)
                    }
                }
                lineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(pointerArr, 3))
                const line = new THREE.Line(lineGeometry, lineMaterial)
                line.rotateX(-Math.PI / 2)
                province.add(line)
            })
        })
        map.add(province)
    })
}
function initText(properties) {
    let center = properties.center || properties.centroid
    const [x, y] = projectpos(center)
    let tag = document.createElement('div')
    tag.innerHTML = properties.name
    tag.style.color = '#fff'
    tag.style.position = 'absolute'
    let label = new CSS2DObject(tag)
    label.element.style.visibility = 'visible'
    label.position.set(x, 2.1, y)
    scene.add(label)
}

function animate() {
    renderer.render(scene, camera)
    labelRenderer.render(scene, camera)
    requestAnimationFrame(animate)
}

export default {
    init
}